package com.kevin.permission.service;

import com.google.common.collect.Lists;
import com.kevin.permission.beans.CacheKeyConstants;
import com.kevin.permission.common.RequestHolder;
import com.kevin.permission.dao.SysAclMapper;
import com.kevin.permission.dao.SysRoleAclMapper;
import com.kevin.permission.dao.SysRoleUserMapper;
import com.kevin.permission.model.SysAcl;
import com.kevin.permission.model.SysUser;
import com.kevin.permission.util.JsonMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SysCoreService {

    @Autowired
    private SysAclMapper sysAclMapper;

    @Autowired
    private SysRoleUserMapper sysRoleUserMapper;

    @Autowired
    private SysRoleAclMapper sysRoleAclMapper;

    @Autowired
    private SysCacheService sysCacheService;

    public List<SysAcl> getCurrentUserAclList() {
        int userId= RequestHolder.getCurrentUser().getId();
        return getUserAclList(userId);
    }

    public List<SysAcl> getUserAclList(int userId) {
        if (isSuperAdmin()){
            return sysAclMapper.getAll();
        }
        List<Integer> userRoleIdList=sysRoleUserMapper.getRoleIdListByUserId(userId);
        if (CollectionUtils.isEmpty(userRoleIdList)){
            return Lists.newArrayList();
        }
        List<Integer> userAclIdList=sysRoleAclMapper.getAclIdListByRoleIdList(userRoleIdList);
        if (CollectionUtils.isEmpty(userAclIdList)){
            return Lists.newArrayList();
        }
        return sysAclMapper.getByIdList(userAclIdList);
    }

    public List<SysAcl> getRoleAclList(int roleId) {
        List<Integer> aclIdList=sysRoleAclMapper.getAclIdListByRoleIdList(Lists.newArrayList(roleId));
        if (CollectionUtils.isEmpty(aclIdList)){
            return Lists.newArrayList();
        }
        return sysAclMapper.getByIdList(aclIdList);
    }


    public boolean isSuperAdmin() {
        // 这里是我自己定义了一个假的超级管理员规则，实际中要根据项目进行修改
        // 可以是配置文件获取，可以指定某个用户，也可以指定某个角色
        SysUser sysUser = RequestHolder.getCurrentUser();
        if (sysUser.getMail().contains("admin")) {
            return true;
        }
        return false;
    }

    public boolean hasUrlAcl(String url) {
//        if (isSuperAdmin()){
//            return true;
//        }
        List<SysAcl> aclList=sysAclMapper.getByUrl(url);
        if (CollectionUtils.isEmpty(aclList)){
            return true;
        }
        //TODO 缓存设置
        List<SysAcl> userAclList=getCurrentUserAclListFromCache();
        Set<Integer> userAclIdSet=userAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());

        boolean hasValidAcl=false;
        // 规则：只要有一个权限点有权限，那么我们就认为有访问权限
        for (SysAcl acl:aclList){
            // 判断一个用户是否具有某个权限点的访问权限
            if (acl==null || acl.getStatus()!=1){ // 权限点无效
                continue;
            }
            hasValidAcl=true;
            if (userAclIdSet.contains(acl.getId())){
                return true;
            }
        }
        if (!hasValidAcl){
            return true;
        }
        return false;

    }

    public List<SysAcl> getCurrentUserAclListFromCache(){
        int userId=RequestHolder.getCurrentUser().getId();
        String cacheValue=sysCacheService.getFromCache(CacheKeyConstants.USER_ACLS,String.valueOf(userId));
        if (StringUtils.isBlank(cacheValue)){
            List<SysAcl> aclList=getCurrentUserAclList();
            if (CollectionUtils.isNotEmpty(aclList)){
                sysCacheService.saveCache(JsonMapper.obj2String(aclList),600,CacheKeyConstants.USER_ACLS,String.valueOf(userId));
            }
            log.info("从数据库中取出:{}",JsonMapper.obj2String(aclList));
            return aclList;
        }

        return JsonMapper.string2Obj(cacheValue, new TypeReference<List<SysAcl>>() {});
    }
}
